package table

import (
	"errors"
	"fmt"
	"reflect"
	"strings"
	"unicode"
	"yunj/pkg/yunj/app/service/admin/adminservice"
	"yunj/pkg/yunj/core/builder/builderconsts"
	tableConsts "yunj/pkg/yunj/core/builder/builderconsts"
	"yunj/pkg/yunj/core/response"
	"yunj/pkg/yunj/util"

	"github.com/gin-gonic/gin"
)

type ColInterface interface {
	GetColField() (field string, err error)                                    // 获取表头字段名
	SetColField(field string) error                                            // 设置表头字段名
	GetColTitle() (title string, err error)                                    // 获取表头标题
	SetColTitle(title string) error                                            // 设置表头标题
	GetColType() (typ string, err error)                                       // 获取表头类型
	SetColType(typ string) error                                               // 设置表头类型
	GetColAlign() (res string, err error)                                      // 获取表头排列方式
	SetColAlign(align string) error                                            // 设置表头排列方式
	GetColSort() (res bool, err error)                                         // 获取表头是否开启列的排序功能
	SetColSort(yes bool) error                                                 // 设置表头是否开启列的排序功能
	GetColFixed() (res string, err error)                                      // 获取表头固定列
	SetColFixed(fixed string) error                                            // 设置表头固定列
	GetColHide() (res string, err error)                                       // 获取表头隐藏列
	SetColHide(hide string) error                                              // 设置表头隐藏列
	SetColAuth(auth string) error                                              // 设置表头权限
	GetColAuth() (auth string, err error)                                      // 获取表头权限
	GetColTemplet() (templet string, err error)                                // 获取表头模板
	SetColTemplet(templet string) error                                        // 设置表头模板
	GetColMinWidth() (res uint64, err error)                                   // 获取表头最小宽度
	SetColMinWidth(minWidth uint64) error                                      // 设置表头最小宽度
	GetError() error                                                           // 获取表头错误
	GetBuilderId() (res string, err error)                                     // 获取构建器ID
	LayModuleExtend() (string, string)                                         // 定义获取layui扩展名称和js文件路径
	LayModuleExtendJs() string                                                 // 定义获取layui扩展js文件路径
	HandleAttr() error                                                         // 处理表头属性
	GetExportValue(value any) any                                              // 获取导出值
	IsRenderCheck() bool                                                       // 是否渲染判断
	RenderHandle(ctx *gin.Context, builderId string) (hasAuth bool, err error) // 渲染处理，返回是否有权限和是否有错误
}

type Col struct {
	Field      string       `json:"field"`    // 表头字段名（唯一标识）
	Title      string       `json:"title"`    // 标题
	Type       string       `json:"type"`     // 类型
	Align      string       `json:"align"`    // 排列方式
	Sort       bool         `json:"sort"`     // 是否开启列的排序功能
	Fixed      string       `json:"fixed"`    // 固定列
	Hide       string       `json:"hide"`     // 隐藏列
	Auth       string       `json:"auth"`     // 权限
	Templet    string       `json:"templet"`  // 模板
	Width      any          `json:"width"`    // 宽度（支持值为：数字、百分比。如： width: 200 / width: '30%）
	MinWidth   uint64       `json:"minWidth"` // 最小宽度
	MaxWidth   uint64       `json:"maxWidth"` // 最大宽度
	BuilderId  string       `json:"-"`        // 构建器id
	GinContext *gin.Context `json:"-"`        // gin上下文
	ErrPrefix  string       `json:"-"`        // 错误前缀
	Err        error        `json:"-"`        // 错误

	// 父结构体属性
	colInstance ColInterface // 表头实例
}

// 设置表头实例
func SetColInstance(c *Col, colInstance ColInterface) {
	c.colInstance = colInstance

	// 获取指针的反射值
	colInstanceValue := reflect.ValueOf(c.colInstance)
	// 检查传入的是否为指针
	if colInstanceValue.Kind() != reflect.Ptr || colInstanceValue.IsNil() {
		c.SetError("请传入表头实例指针值！")
	}

	// Type=normal，且templet未设置的情况下，设置默认的模板
	typ, err := colInstance.GetColType()
	if err == nil && typ == tableConsts.TABLE_COL_TYPE_NORMAL {
		templet, err := colInstance.GetColTemplet()
		if templet == "" && err == nil {
			colInstance.SetColTemplet(util.TypeName(c.colInstance))
		}
	}
}

// 获取表头字段名
func (c *Col) GetColField() (field string, err error) {
	err = c.GetError()
	if err != nil {
		return
	}
	field = c.Field
	return
}

// 设置表头字段名
func (c *Col) SetColField(field string) (err error) {
	err = c.GetError()
	if err != nil {
		return
	}
	c.Field = field
	return
}

// 获取表头标题
func (c *Col) GetColTitle() (title string, err error) {
	err = c.GetError()
	if err != nil {
		return
	}
	title = c.Title
	return
}

// 设置表头标题
func (c *Col) SetColTitle(title string) (err error) {
	err = c.GetError()
	if err != nil {
		return
	}
	c.Title = title
	return
}

// 获取表头类型
func (c *Col) GetColType() (res string, err error) {
	err = c.GetError()
	if err != nil {
		return
	}
	res = c.Type
	return
}

// 设置表头类型
func (c *Col) SetColType(typ string) (err error) {
	err = c.GetError()
	if err != nil {
		return
	}
	c.Type = typ
	return
}

// 获取表头排列方式
func (c *Col) GetColAlign() (res string, err error) {
	err = c.GetError()
	if err != nil {
		return
	}
	res = c.Align
	return
}

// 设置表头排列方式
func (c *Col) SetColAlign(align string) (err error) {
	err = c.GetError()
	if err != nil {
		return
	}
	c.Align = align
	return
}

// 获取表头是否开启列的排序功能
func (c *Col) GetColSort() (res bool, err error) {
	err = c.GetError()
	if err != nil {
		return
	}
	res = c.Sort
	return
}

// 设置表头是否开启列的排序功能
func (c *Col) SetColSort(yes bool) (err error) {
	err = c.GetError()
	if err != nil {
		return
	}
	c.Sort = yes
	return
}

// 获取表头固定列
func (c *Col) GetColFixed() (res string, err error) {
	err = c.GetError()
	if err != nil {
		return
	}
	res = c.Fixed
	return
}

// 设置表头固定列
func (c *Col) SetColFixed(fixed string) (err error) {
	err = c.GetError()
	if err != nil {
		return
	}
	c.Fixed = fixed
	return
}

// 获取表头隐藏列
func (c *Col) GetColHide() (res string, err error) {
	err = c.GetError()
	if err != nil {
		return
	}
	res = c.Hide
	return
}

// 设置表头隐藏列
func (c *Col) SetColHide(hide string) (err error) {
	err = c.GetError()
	if err != nil {
		return
	}
	c.Hide = hide
	return
}

// 获取表头权限
func (c *Col) GetColAuth() (auth string, err error) {
	err = c.GetError()
	if err != nil {
		return
	}
	auth = c.Auth
	return
}

// 设置表头权限
func (c *Col) SetColAuth(auth string) (err error) {
	err = c.GetError()
	if err != nil {
		return
	}
	c.Auth = auth
	return
}

// 获取表头模板
func (c *Col) GetColTemplet() (templet string, err error) {
	err = c.GetError()
	if err != nil {
		return
	}
	templet = c.Templet
	return
}

// 设置表头模板
func (c *Col) SetColTemplet(templet string) (err error) {
	err = c.GetError()
	if err != nil {
		return
	}
	c.Templet = templet
	return
}

// 获取表头最小宽度
func (c *Col) GetColMinWidth() (res uint64, err error) {
	err = c.GetError()
	if err != nil {
		return
	}
	res = c.MinWidth
	return
}

// 设置表头最小宽度
func (c *Col) SetColMinWidth(minWidth uint64) (err error) {
	err = c.GetError()
	if err != nil {
		return
	}
	c.MinWidth = minWidth
	return
}

// 获取构建器ID
func (c *Col) GetBuilderId() (res string, err error) {
	err = c.GetError()
	if err != nil {
		return
	}
	res = c.BuilderId
	return
}

// 设置构建器ID
func (c *Col) setBuilderId(builderId string) (err error) {
	err = c.GetError()
	if err != nil {
		return
	}
	c.BuilderId = builderId
	return
}

// 设置表头实例的gin上下文
func (c *Col) setGinContext(ctx *gin.Context) (err error) {
	err = c.GetError()
	if err != nil {
		return
	}
	c.GinContext = ctx
	return
}

// 获取表头实例的错误前缀
func (c *Col) getErrPrefix() (prefix string, err error) {
	err = c.GetError()
	if err != nil {
		return
	}
	prefix = c.ErrPrefix
	return
}

// 设置表头实例的错误前缀
func (c *Col) setErrPrefix(prefix string) (err error) {
	err = c.GetError()
	if err != nil {
		return
	}
	c.ErrPrefix = prefix
	return
}

// 获取表头错误
func (c *Col) GetError() error {
	return c.Err
}

// 设置表头错误
func (c *Col) SetError(err any) error {
	if _err := c.GetError(); _err != nil {
		return _err
	}
	var resErrMsg string
	if _errMsg, ok := err.(string); ok {
		resErrMsg = _errMsg
	} else if _err, ok := err.(error); ok {
		resErrMsg = _err.Error()
	} else {
		resErrMsg = "未知错误！"
	}

	// 错误前缀
	errPrefix, _ := c.getErrPrefix()
	if errPrefix == "" {
		errPrefix = fmt.Sprintf("表头[%s]", c.Field)
		c.setErrPrefix(errPrefix)
	}

	if !strings.HasPrefix(resErrMsg, errPrefix) {
		resErrMsg = errPrefix + resErrMsg
	}
	newErr := errors.New(resErrMsg)
	c.Err = newErr
	return newErr
}

// 定义获取layui扩展名称和js文件路径
func (c *Col) LayModuleExtend() (name string, js string) {
	templet, _ := c.GetColTemplet()
	name = "TableCol" + templet
	js = c.colInstance.LayModuleExtendJs()
	return
}

// 定义获取layui扩展js文件路径
func (c *Col) LayModuleExtendJs() string {
	// 默认路径
	if util.PackageFullName(c.colInstance) == "yunj/pkg/yunj/core/builder/table/col" {
		var jsFileNameRes strings.Builder
		if templet, _ := c.GetColTemplet(); templet != "" {
			for i, char := range templet {
				if i > 0 && unicode.IsUpper(char) {
					jsFileNameRes.WriteByte('-')
				}
				jsFileNameRes.WriteRune(unicode.ToLower(char))
			}
			jsFileName := jsFileNameRes.String()
			return util.YunjStaticUrl("/static/yunj/js/modules/table/templet/cols/" + jsFileName + ".min")
		}
	}
	return ""
}

// 处理表头属性
func (c *Col) HandleAttr() error {
	return nil
}

// 获取导出值
func (c *Col) GetExportValue(value any) any {
	return value
}

// 是否渲染判断
func (c *Col) IsRenderCheck() bool {
	return true
}

// 渲染处理
// @param builderId: 构建器id
// @return ok: 是否渲染
// @return err: 错误消息
func (c *Col) RenderHandle(ctx *gin.Context, builderId string) (ok bool, err error) {
	err = c.setBuilderId(builderId)
	if err != nil {
		return
	}
	// 设置gin上下文
	c.setGinContext(ctx)
	if err = c.GetError(); err != nil {
		return
	}
	// 判断权限
	auth, _ := c.GetColAuth()
	hasAuth := adminservice.CheckAuth(ctx, auth)
	if !hasAuth {
		return
	}
	// 处理表头属性
	err = c.colInstance.HandleAttr()
	if err != nil {
		err = c.SetError(err)
		return
	}
	// align
	var alignVal string
	alignVal, err = c.GetColAlign()
	if err != nil {
		err = c.SetError(err)
		return
	}
	if alignVal == "" {
		alignVal = builderconsts.ALIGN_LEFT
		err = c.SetColAlign(alignVal)
		if err != nil {
			err = c.SetError(err)
			return
		}
	}
	// minWidth
	var minWidth uint64
	minWidth, err = c.GetColMinWidth()
	if err != nil {
		err = c.SetError(err)
		return
	}
	if minWidth == 0 {
		minWidth = 80
		err = c.SetColMinWidth(minWidth)
		if err != nil {
			err = c.SetError(err)
			return
		}
	}
	err = c.GetError()
	if err != nil {
		return
	}
	// 是否渲染判断
	ok = c.colInstance.IsRenderCheck()
	if !ok {
		return
	}
	// 输出lay扩展
	name, js := c.LayModuleExtend()
	response.SetCtxRenderLayModuleExtend(ctx, name, js)
	return
}
